package com.itheima.wms.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.ImmutableMap;
import com.itheima.wms.common.enums.StockRecordType;
import com.itheima.wms.common.enums.StockRecordWay;
import com.itheima.wms.common.service.CrudServiceImpl;
import com.itheima.wms.dao.OutboundListMapper;
import com.itheima.wms.dao.OutboundMapper;
import com.itheima.wms.dao.PickingMapper;
import com.itheima.wms.dao.StockRecordMapper;
import com.itheima.wms.dto.OutboundListBatchDTO;
import com.itheima.wms.entity.*;
import com.itheima.wms.service.OutboundListService;
import com.itheima.wms.service.StockService;
import com.itheima.wms.vo.OutboundListDetailVO;
import com.itheima.wms.vo.OutboundListSumVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;


/**
 * <p>
 * 业务实现类
 * 出库清单
 * </p>
 */
@Slf4j
@Service
public class OutboundListServiceImpl extends CrudServiceImpl<OutboundListMapper, OutboundListEntity> implements OutboundListService {

    @Autowired
    private StockService stockService;
    @Autowired
    private OutboundMapper outboundMapper;
    @Autowired
    private PickingMapper pickingMapper;
    @Autowired
    private StockRecordMapper stockRecordMapper;


    @Override
    @Transactional
    public Boolean saveBatchByStockIds(OutboundListBatchDTO outboundListBatchDTO) {
        List<StockEntity> stockEntities = stockService.listByIds(outboundListBatchDTO.getStockIds());
        List<OutboundListEntity> outboundListEntities = new ArrayList<>();
        for (StockEntity stockEntity : stockEntities) {
            outboundListEntities.add(OutboundListEntity.builder().masterId(outboundListBatchDTO.getMasterId()).stockId(stockEntity.getId()).status(1).build());
        }
        return this.saveBatch(outboundListEntities);
    }

    @Override
    public IPage<OutboundListDetailVO> pageDetail(Page<OutboundListDetailVO> page, Map data) {
        IPage<OutboundListDetailVO> iPage = this.baseMapper.selectOutboundListDetail(page, data);
        return iPage;
    }

    @Override
    public OutboundListSumVO getSumByMasterId(Long masterId) {
        return this.baseMapper.sumOutboundListDetail(ImmutableMap.of("masterId", masterId));
    }

    @Override
    public List stockIds(Map data) {
        LambdaQueryWrapper<OutboundListEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(OutboundListEntity::getStockId);
        wrapper.eq(OutboundListEntity::getMasterId, data.get("masterId"));
        List ids = this.baseMapper.selectObjs(wrapper);
        return ids;
    }

    @Override
    public OutboundListSumVO sumOutboundListDetail(Map<String, Long> params) {
        return this.baseMapper.sumOutboundListDetail(params);
    }

    @Override
    public void cancelBatch(List<OutboundListEntity> outboundListEntities) {
        outboundListEntities.forEach(outboundListEntity -> unfreeze(outboundListEntity));
    }

    @Override
    @Transactional
    public boolean updateById(OutboundListEntity entity) {
        OutboundListEntity dbEntity = this.getById(entity.getId());
        if (null != entity.getPickingNum()) {
            entity.setDifferenceNum(entity.getPickingNum() - dbEntity.getOutboundNum());
        }
        boolean result = super.updateById(entity);
        dbEntity = this.getById(entity.getId());

        // 货品数量汇总
        if (null != entity.getOutboundNum()) {
            QueryWrapper<OutboundListEntity> queryWrapper = new QueryWrapper<>();
            queryWrapper.select("IFNULL(sum(outbound_num),0) as totalNum")
                    .eq("master_id", dbEntity.getMasterId());

            Map<String, Object> map = this.getMap(queryWrapper);
            Integer totalNum = ((java.math.BigDecimal) map.get("totalNum")).intValue();

            outboundMapper.updateById(OutboundEntity.builder().id(dbEntity.getMasterId()).goodsNum(totalNum).build());

            Integer dbOutboundNum = dbEntity.getOutboundNum();
            // 冻结库存
            frozen(dbEntity, dbOutboundNum);

        }
        // 实拣数量
        if (null != entity.getPickingNum()) {
            QueryWrapper<OutboundListEntity> queryWrapper = new QueryWrapper<>();
            queryWrapper.select("IFNULL(sum(picking_num),0) as totalNum,IFNULL(sum(abs(difference_num)),0) as differenceNum")
                    .eq("master_id", dbEntity.getMasterId());
            Map<String, Object> map = this.getMap(queryWrapper);
            Integer totalNum = ((java.math.BigDecimal) map.get("totalNum")).intValue();
            Integer differenceNum = ((java.math.BigDecimal) map.get("differenceNum")).intValue();

            LambdaQueryWrapper<PickingEntity> updateWrapper = new LambdaQueryWrapper<>();
            updateWrapper.eq(PickingEntity::getMasterId, dbEntity.getMasterId());
            pickingMapper.update(PickingEntity.builder().realNum(totalNum).differenceNum(differenceNum).build(), updateWrapper);

            Integer dbPickingNum = dbEntity.getPickingNum();
            // 冻结库存
            frozen(dbEntity, dbPickingNum);
        }

        return result;
    }

    @Override
    @Transactional
    public boolean removeByIds(Collection<? extends Serializable> idList) {
        idList.forEach(id -> unfreeze(this.getById(id)));
        return super.removeByIds(idList);
    }

    /**
     * 冻结库存
     *
     * @param dbEntity
     */
    private void frozen(OutboundListEntity dbEntity, Integer num) {
        // 库存冻结  增加库存操作记录

        StockEntity stockEntity = stockService.getById(dbEntity.getStockId());
        Integer original = stockEntity.getTotal();
        Integer originalFree = stockEntity.getFree();

        LambdaQueryWrapper<StockRecordEntity> stockRecordWrapper = new LambdaQueryWrapper<>();
        stockRecordWrapper.eq(StockRecordEntity::getSourceId, dbEntity.getId());
        stockRecordWrapper.last("limit 1");
        StockRecordEntity stockRecordEntity = stockRecordMapper.selectOne(stockRecordWrapper);
        if (null == stockRecordEntity) {
            stockRecordEntity = new StockRecordEntity();
            stockRecordEntity.setSourceId(dbEntity.getId());
            stockRecordEntity.setLocationId(stockEntity.getLocationId());
            stockRecordEntity.setType(StockRecordType.CK.getCode());// 类型出库
            stockRecordEntity.setOriginal(original);
            stockRecordEntity.setOriginalFree(originalFree);
            stockRecordEntity.setWay(StockRecordWay.FROZEN.getCode());
            stockRecordEntity.setAlteration(num);
            stockRecordEntity.setResult(stockRecordEntity.getOriginal());
            stockRecordEntity.setResultFree(stockRecordEntity.getOriginalFree() - stockRecordEntity.getAlteration());
            stockRecordMapper.insert(stockRecordEntity);
            stockService.frozen(stockEntity.getId(), stockRecordEntity.getAlteration()); // 冻结记录
        } else {
            Integer oldChange = stockRecordEntity.getAlteration();
            stockService.unfreeze(stockEntity.getId(), oldChange); // 解冻原记录

            stockRecordEntity.setOriginal(original);
            stockRecordEntity.setOriginalFree(originalFree);
            stockRecordEntity.setAlteration(num);
            stockRecordEntity.setResult(stockRecordEntity.getOriginal());
            stockRecordEntity.setResultFree(stockRecordEntity.getOriginalFree() - stockRecordEntity.getAlteration());
            stockRecordMapper.updateById(stockRecordEntity);
            stockService.frozen(stockEntity.getId(), stockRecordEntity.getAlteration()); // 冻结记录
        }
    }

    /**
     * 冻结库存
     *
     * @param dbEntity
     */
    private void unfreeze(OutboundListEntity dbEntity) {
        log.info("解冻出库明细：{}", dbEntity);
        int num = dbEntity.getOutboundNum();
        if (null != dbEntity.getPickingNum() && dbEntity.getPickingNum() > 0) {
            num = dbEntity.getPickingNum();
        }

        if (num <= 0) {
            log.info("无需解冻:{}", dbEntity);
            return;
        }

        // 库存冻结  增加库存操作记录
        StockEntity stockEntity = stockService.getById(dbEntity.getStockId());
        Integer original = stockEntity.getTotal();
        Integer originalFree = stockEntity.getFree();

        stockService.unfreeze(stockEntity.getId(), num); // 解冻记录

        StockRecordEntity stockRecordEntity = new StockRecordEntity();
        stockRecordEntity.setSourceId(dbEntity.getId());
        stockRecordEntity.setLocationId(stockEntity.getLocationId());
        stockRecordEntity.setType(StockRecordType.CK.getCode());// 类型出库
        stockRecordEntity.setOriginal(original);
        stockRecordEntity.setOriginalFree(originalFree);
        stockRecordEntity.setWay(StockRecordWay.UNFREEZE.getCode());
        stockRecordEntity.setAlteration(num);
        stockRecordEntity.setResult(stockRecordEntity.getOriginal());
        stockRecordEntity.setResultFree(stockRecordEntity.getOriginalFree() + stockRecordEntity.getAlteration());
        stockRecordMapper.insert(stockRecordEntity);
    }
}

